/*
  XXX DOES NOT USE BUILT-IN DETECTION FUNCTION XXX

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Office Excel DV record buffer overflow attempt"; flowbits:isset,file.xls; flow:to_client,established; content:"|b2 01 12 00|"; content:"|be 01|"; distance:18; within:2; metadata:policy security-ips drop; reference:cve,2011-0105; reference:url,technet.microsoft.com/en-us/security/bulletin/MS11-021; classtype:attempted-user; sid:18676; rev:1;)
*/
/*
 * Vuln Title: XXXX
 *
 * Copyright (C) 2005-2010 Sourcefire, Inc. All Rights Reserved
 *
 * Written by XXXX, Sourcefire VRT <XXXX@sourcefire.com>
 *
 * Auto-generated by XXXX
 *
 * This file may contain proprietary rules that were created, tested and
 * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
 * rules that were created by Sourcefire and other third parties and
 * distributed under the GNU General Public License (the "GPL Rules").  The
 * VRT Certified Rules contained in this file are the property of
 * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
 * The GPL Rules created by Sourcefire, Inc. are the property of
 * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
 * Reserved.  All other GPL Rules are owned and copyrighted by their
 * respective owners (please see www.snort.org/contributors for a list of
 * owners and their respective copyrights).  In order to determine what
 * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
 * Certified Rules License Agreement.
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule18676eval(void *p);

/* declare rule data structures */
/* flowbits:isset "file.xls"; */
static FlowBitsInfo rule18676flowbits0 =
{
    "file.xls",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule18676option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule18676flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule18676flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule18676option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule18676flow1
    }
};
// content:"|B2 01 12 00|", depth 0, fast_pattern; 
static ContentInfo rule18676content2 = 
{
    (uint8_t *) "|B2 01 12 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule18676option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule18676content2
    }
};
// content:"|BE 01|", offset 18, depth 2, relative; 
static ContentInfo rule18676content3 = 
{
    (uint8_t *) "|BE 01|", /* pattern (now in snort content format) */
    2, /* depth */
    18, /* offset */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule18676option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule18676content3
    }
};

/* references for sid 18676 */
/* reference: cve "2011-0105"; */
static RuleReference rule18676ref1 = 
{
    "cve", /* type */
    "2011-0105" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS11-021"; */
static RuleReference rule18676ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS11-021" /* value */
};

static RuleReference *rule18676refs[] =
{
    &rule18676ref1,
    &rule18676ref2,
    NULL
};
/* metadata for sid 18676 */
static RuleMetaData rule18676policy1 =
{
   "policy max-detect-ips drop"
};

static RuleMetaData rule18676service1 =
{
    "service http"
};

static RuleMetaData *rule18676metadata[] =
{
    &rule18676service1,
    &rule18676policy1,
    NULL
};

RuleOption *rule18676options[] =
{
    &rule18676option0,
    &rule18676option1,
    &rule18676option2,
    &rule18676option3,
    NULL
};

Rule rule18676 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       18676, /* sigid */
       11, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OFFICE Microsoft Office Excel DV record buffer overflow attempt",     /* message */
       rule18676refs /* ptr to references */
       ,rule18676metadata
   },
   rule18676options, /* ptr to rule options */
   &rule18676eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
// #if 0 // Don't compile the detection functions if they're not used
int rule18676eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *end_of_payload, *cursor_detect;
    uint8_t  valType;
    uint16_t cch, cce;
    int i;
        
    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    DEBUG_SO(printf("enter rule18676eval\n");)

    // flowbits:isset "file.xls";
    if (processFlowbits(p, rule18676options[0]->option_u.flowBit) <= 0)
        return RULE_NOMATCH;

    // flow:established, to_client;
    if (checkFlow(p, rule18676options[1]->option_u.flowFlags) <= 0) 
        return RULE_NOMATCH;

    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
        return RULE_NOMATCH;

    // content:"|B2 01 12 00|", depth 0, fast_pattern;
    while (contentMatch(p, rule18676options[2]->option_u.content, &cursor_normal) > 0) 
    {
        cursor_detect = cursor_normal; 

        // content:"|BE 01|", offset 18, depth 2, relative;
        if (contentMatch(p, rule18676options[3]->option_u.content, &cursor_detect) > 0) 
        {
            DEBUG_SO(printf("found DV record\n");)            

            // in order to have the formula2.cce field, there should be at least 28 bytes left 
            if (cursor_detect + 28 > end_of_payload) 
                return RULE_NOMATCH;

            // valType of 1, 2, 4, 5, or 6 (4 bit field)
            valType = *(cursor_detect + 2) & 0x0F;
            DEBUG_SO(printf("valType: 0x%02x\n", valType);)

            // if not valid value, loop to try again
            if(valType == 0 || valType == 3 || valType > 6)
               break;

            // typeOperator (we care about 0 or 1) (4 bit field)
            DEBUG_SO(printf("typeOperator: 0x%02x\n", ((*(cursor_detect + 4) >> 4) & 0xF0)));

            // We only care if typeOperator (the upper nibble of the fifth byte) is 0 or 1
            if(*(cursor_detect + 4) & 0xE0)
                break;
 
            cursor_detect += 6;  
            
            // Skip PromptTitle, ErrorTitle, Prompt, Error XLUnicodeString structures  
            for (i = 0; i < 4; i++)
            {
                // when i == 0, we know there are enough data
                cch = read_little_16(cursor_detect);
                DEBUG_SO(printf("XLUnicodeString.cch: 0x%02x\n", cch);)
                
                if (*(cursor_detect + 2) & 1) // if fHighByte bit is set, the array size is cch * 2 (wide char array)
                    cch *= 2;

                cursor_detect += 3 + cch;          

                // I've put cursor_detect checking here so that we don't need to do 
                // another checking right after exiting this for-loop 
                if (cursor_detect + 3 > end_of_payload)
                    return RULE_NOMATCH; 
            }

            cce = read_little_16(cursor_detect);  
            DEBUG_SO(printf("formula1.cce: 0x%02x\n", cce);)             
            cursor_detect += cce + 4;

            if (cursor_detect + 2 > end_of_payload)
                return RULE_NOMATCH;

            cce = read_little_16(cursor_detect); 
            DEBUG_SO(printf("formula2.cce: 0x%02x\n", cce);)
            if (cce == 0) {
                return RULE_MATCH;
            }
        }
     }
    
     return RULE_NOMATCH;
}
// #endif // 0 Don't compile the detection functions if they're not used
/*
Rule *rules[] = {
    &rule18676,
    NULL
};
*/
